Skip to content

feat: open source main app#2

Merged
gameroman merged 6 commits intomainfrom
oss-web-app
Mar 24, 2026
Merged

feat: open source main app#2
gameroman merged 6 commits intomainfrom
oss-web-app

Conversation

@gameroman
Copy link
Member

@gameroman gameroman commented Mar 24, 2026

Summary by CodeRabbit

  • New Features

    • New app with user and admin dashboards, submission forms for proven/disproven elements, client-side submission UI, and an API to fetch element datasets.
    • New UI primitives (Button, Link, Divider) and dashboard sections to collect and show submission feedback.
    • Git-backed read/write utilities and data merge/validation helpers for storing element data.
  • Infrastructure

    • CI job renamed to “Test and Build”; Node.js setup added and tests run before builds.
    • Tailwind + Astro configured; .env now ignored.
  • Tests

    • Added unit tests for data-merge logic.

@gameroman gameroman self-assigned this Mar 24, 2026
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 24, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
history dbc30db Commit Preview URL

Branch Preview URL
Mar 24 2026, 07:27 PM

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

Warning

Rate limit exceeded

@gameroman has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 1 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6624e777-a276-4113-931c-7319be82e3e8

📥 Commits

Reviewing files that changed from the base of the PR and between 1548c2b and dbc30db.

📒 Files selected for processing (1)
  • apps/icbe/src/utils/submit-elements.ts
📝 Walkthrough

Walkthrough

Adds a new Astro-based ICBE app (Solid + Tailwind) with Cloudflare Worker runtime, Zod schemas, GitLab-backed JSON storage, server actions for submitting elements, utilities for merging/persisting data, UI components, tests, and CI/workspace script updates.

Changes

Cohort / File(s) Summary
CI & VCS
.github/workflows/ci.yml, .gitignore
CI test job now sets up Node.js (24.x) before Bun, renamed job to “Test and Build”, added explicit “Run tests” step; .env added to .gitignore.
App Config & Tooling
apps/icbe/astro.config.ts, apps/icbe/wrangler.jsonc, apps/icbe/tsconfig.json, apps/icbe/tailwind.config.ts
New Astro config (Cloudflare adapter, Solid integration, Tailwind via Vite, site URL, env schema), Wrangler config, TS config for Solid JSX, and Tailwind config.
Package manifests & scripts
apps/icbe/package.json, package.json
App imports map and added dependencies/scripts (typegen, test); root workspace adds tailwindcss/@tailwindcss/vite and root typegen/test scripts.
Pages & API routes
apps/icbe/src/pages/...
apps/icbe/src/pages/index.astro, apps/icbe/src/pages/dashboard/index.astro, apps/icbe/src/pages/admin/dashboard.astro, apps/icbe/src/pages/api/get-elements.ts
New home, dashboard, admin pages (some include runtime redirect checks) and a GET API returning proven and disproven lists.
Layouts & Assets
apps/icbe/src/layouts/Layout.astro, apps/icbe/src/styles/global.css, apps/icbe/public/.assetsignore
New layout with meta tags and slot, global Tailwind import, and assets ignore entries for ._worker.js and ._routes.json.
UI primitives
apps/icbe/src/components/ui/Button.tsx, .../Link.tsx, .../Divider.tsx
Typed SolidJS Button, Link, Divider components with Tailwind classes and controlled prop shapes.
Dashboard components
apps/icbe/src/components/...
UserDashboard.tsx, AdminDashboard.tsx, dashboard/SubmitDisprovenElementsSection.tsx, dashboard/SubmitProvenElementsSection.tsx
User/Admin dashboards and two submission sections that collect input, manage submit state, invoke server actions, and render feedback.
Server actions
apps/icbe/src/actions/submit-elements.ts, apps/icbe/src/actions/index.ts
Two Astro server actions (submitDisprovenElements, submitProvenElements) with Zod validation, auth/permission gates (placeholders), and calls into save/merge utilities; actions re-exported.
Schemas
apps/icbe/src/schemas/data/*.ts, apps/icbe/src/schemas/index.ts
Zod schemas and inferred types for proven/disproven, metadata, history; central data index exporting schemas and re-exported at top-level.
Server utilities
apps/icbe/src/utils/gitlab.ts, .../submit-elements.ts, .../merge-data.ts, .../respond-json.ts
GitLab client helpers to read/write validated JSON, functions to build SaveToCloud payloads (merge/dedupe, update metadata/history), mergeProvenData, and respondWithJSON.
Tests
apps/icbe/tests/index.test.ts
Bun test verifying mergeProvenData merges existing and new proven entries by name and combines nested fields.
Misc
apps/icbe/package.json, apps/icbe/public/.assetsignore
Adds .assetsignore entries and app-level package manifest updates (imports map, deps, scripts).

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Form as Dashboard Form
    participant ServerAction as Astro Action
    participant Utils as Server Utils
    participant GitLab as GitLab API

    Client->>Form: fill & submit
    Form->>ServerAction: invoke submitDisprovenElements / submitProvenElements
    ServerAction->>ServerAction: Zod validate, auth/perm checks
    ServerAction->>Utils: build SaveToCloudData (merge/dedupe, update meta/history)
    Utils->>GitLab: fetch existing JSON files (elements, meta, history)
    Utils->>Utils: merge/deduplicate and prepare commit actions
    ServerAction->>GitLab: commit updated JSON files
    GitLab-->>ServerAction: commit response
    ServerAction-->>Form: return success/error
    Form->>Client: display result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through schemas and stitched every line,

Merged bits of data and proof so fine,
Actions trimmed and commits set to send,
ICBE now readies a Cloudflare friend! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'feat: open source main app' is vague and does not clearly reflect the substantial changeset, which primarily introduces a new Astro-based web application at apps/icbe with GitLab integration. Consider a more descriptive title such as 'feat: add icbe astro web app with gitlab integration' or 'feat: create user/admin dashboard with element submission' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch oss-web-app

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🧹 Nitpick comments (5)
apps/icbe/src/pages/index.astro (1)

6-8: Consider providing actual metadata values for SEO.

Setting title, description, and canonical to null may result in missing or default meta tags, which could negatively impact SEO and social sharing. If these are intentional placeholders, consider adding a TODO comment or providing sensible defaults.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/pages/index.astro` around lines 6 - 8, The metadata variables
title, description, and canonical are set to null which yields missing meta
tags; replace these nulls in the index page by assigning sensible defaults or
environment-driven values (e.g., a site title string, a short description, and
the canonical URL) or, if intentionally left blank, add TODO comments next to
the constants to make the intent explicit; update the constants named title,
description, and canonical so downstream head/meta rendering has real values or
clear TODOs.
apps/icbe/src/pages/dashboard/index.astro (1)

9-9: Hardcoded canSubmitElements = false disables functionality.

This permanently disables the element submission UI. If this is intentional for the initial open-source release, consider adding a comment explaining when/how this would be enabled.

+// TODO: Enable when authentication is implemented
 const canSubmitElements = false;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/pages/dashboard/index.astro` at line 9, The file currently
hardcodes canSubmitElements = false which disables the element submission UI;
replace the hardcoded value with a proper feature flag or config check (e.g.,
read from an environment/config value or a feature toggle) where
canSubmitElements is computed at runtime, or if the false value is intentional
for the public release add a clear inline comment next to the canSubmitElements
declaration explaining that it is intentionally disabled and describing when/how
it will be enabled (e.g., via ENABLE_ELEMENT_SUBMIT env var or a
backend-permission check) and reference the variable name canSubmitElements in
your change.
apps/icbe/src/utils/respond-json.ts (1)

3-10: Allow status/headers override in respondWithJSON.

Right now every response is forced to 200, which limits callers that need structured JSON errors.

💡 Suggested refactor
 export function respondWithJSON<T extends JsonLike>(
   data: T,
+  init: ResponseInit = {},
 ): { response: Response; data: T } {
-  const response = new Response(JSON.stringify(data), {
-    headers: { "Content-Type": "application/json" },
-    status: 200,
-  });
+  const headers = new Headers(init.headers);
+  if (!headers.has("Content-Type")) {
+    headers.set("Content-Type", "application/json");
+  }
+  const response = new Response(JSON.stringify(data), {
+    ...init,
+    status: init.status ?? 200,
+    headers,
+  });
   return { response, data };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/utils/respond-json.ts` around lines 3 - 10, The respondWithJSON
function always forces status 200 and fixed headers; change its signature
(respondWithJSON<T extends JsonLike>(data: T, options?: { status?: number;
headers?: HeadersInit })) so callers can override status and headers; merge
default headers { "Content-Type": "application/json" } with options.headers and
use options.status || 200 for the Response creation inside respondWithJSON to
construct the Response with the requested status and headers and return {
response, data } as before.
apps/icbe/src/components/UserDashboard.tsx (1)

19-31: isAdmin is hardcoded to false, so admin navigation is dead code.

On Line 19, this permanently disables the admin link path. Prefer deriving this from props/session state.

💡 Suggested refactor
 export default function UserDashboard(props: {
   canSubmitElements: boolean;
+  isAdmin?: boolean;
 }): JSX.Element {
-  const isAdmin = false;
+  const isAdmin = props.isAdmin ?? false;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/components/UserDashboard.tsx` around lines 19 - 31, The
UserDashboard currently hardcodes isAdmin = false which makes the admin
navigation unreachable; replace the hardcoded flag by deriving admin status from
real state (accept an isAdmin prop on the UserDashboard component or call the
app's auth/session hook to get the current user's roles) and use that value in
the existing Show conditional that wraps Divider/Link (retain TopBar, Show and
Link usage). Ensure the prop or session-derived value is a boolean named isAdmin
so existing conditional logic (Show when={isAdmin}) continues to work.
apps/icbe/package.json (1)

14-14: Use bun test as the recommended command for running tests.

On Line 14, use "bun test" instead of "bun run test". While bun run test functions correctly, Bun's official documentation recommends using bun test directly in package.json scripts as it avoids unnecessary overhead from the bun run wrapper.

💡 Suggested fix
-    "test": "bun run test",
+    "test": "bun test",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/package.json` at line 14, The package.json "test" script currently
uses the wrapper invocation "bun run test"; update the "test" script value to
use the direct Bun command "bun test" instead (edit the "test" entry in
package.json) so the script invokes bun test directly per Bun recommendations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/icbe/src/actions/submit-elements.ts`:
- Around line 58-59: The code calls getProvenToSave(...) which ultimately uses
getUpdatedMetaInfo(...) but incorrectly passes type: "disproven", causing proven
submissions to persist as disproven; update the helper in
apps/icbe/src/utils/submit-elements.ts so getUpdatedMetaInfo(...) receives the
correct classification (e.g., type: "proven" or a value derived from the actual
submission result) when building the meta/history payload, and ensure
getProvenToSave and the call sites (getProvenToSave, saveToCloud) propagate that
corrected type so saved metadata reflects the true proven status.
- Around line 10-25: The authorization checks are using hard-coded values (role
and canSubmitElements) so submissions always throw; update the handlers in
submit-elements.ts to derive role and permissions from the request/session
context (e.g., use the incoming context or session object available to the
action) instead of setting const role = null and const canSubmitElements =
false, and use those real values in the existing if-blocks that throw
ActionError (retain the same error shapes). Locate the checks referencing role
and canSubmitElements in the file (also repeated around lines 40-55) and replace
them with lookups like context.session.role or an authorization helper that
evaluates whether the current user canSubmitElements.

In `@apps/icbe/src/components/dashboard/SubmitDisprovenElementsSection.tsx`:
- Around line 12-29: The result container currently only shows feedback when
props.state.status === "complete", so errors set as status === "error" (from the
submission paths) are not shown; update SubmitDisprovenElementsResultContainer
to render for both complete and error statuses (e.g., Show when
props.state.status === "complete" || props.state.status === "error") and use the
passed-in state.success or state.status to decide styling and message so
rejected submissions display an error message; ensure you reference the same
Show usage and the props.state value in the component.
- Around line 63-65: The textarea in SubmitDisprovenElementsSection.tsx forces
white text via the class "text-white" without a matching dark background, making
input unreadable on the default light textarea; update the textarea's class list
to either remove "text-white" (so it uses the default/OS colors) or pair it with
a dark background utility (e.g., add a bg-slate-800 or bg-gray-900 class and
appropriate focus/border classes) and ensure placeholder styling remains
visible; locate the <textarea> in the SubmitDisprovenElementsSection component
and adjust the class/className accordingly.

In `@apps/icbe/src/components/dashboard/SubmitProvenElementsSection.tsx`:
- Around line 41-67: In SubmitProvenElementsSection update the onInput handlers
so clearing a field does not write falsy placeholders into props.element: for
the steps handler (referencing props.element, props.baseElement, setElement,
steps) only set steps to Number(value) when e.currentTarget.value !== "" and
otherwise delete or omit the steps key from the base-element object (or set it
to undefined); similarly for the proof handler (proof, proof.url) if
e.currentTarget.value === "" remove the proof object (or set proof to undefined)
instead of writing an empty string—ensure you merge with the previous
base-element content so other fields are preserved.
- Around line 16-31: SubmitProvenElementsResultContainer only renders when
props.state.status === "complete", so users never see the error state set
elsewhere; update the Show condition to render for both completion and error
(e.g., props.state.status === "complete" || props.state.status === "error") and
change the error branch to display a specific message from the state (use
state.error or state.message if present, falling back to "Elements submission
failed.") so SubmitProvenElementsResultContainer and the SubmitState error
payload are visible to users.

In `@apps/icbe/src/layouts/Layout.astro`:
- Around line 18-21: The viewport meta in Layout.astro currently disables
pinch-zoom by setting maximum-scale and user-scalable; update the <meta
name="viewport"> tag used in Layout.astro to allow zooming (e.g., remove
maximum-scale and user-scalable attributes or set maximum-scale to a reasonable
value and user-scalable to yes) so mobile users can pinch-zoom and text scaling
is not blocked.

In `@apps/icbe/src/pages/admin/dashboard.astro`:
- Around line 5-7: The current check using Math.random() with Astro.redirect is
a placeholder and must be replaced with real auth: remove the Math.random()
condition and instead validate the incoming request's session/token (e.g., call
your auth helper such as getSessionFromRequest or verifyAuth against
Astro.request or Astro.locals) and check authorization (e.g., isAdmin or
requireAdmin); if the user is unauthenticated or not an admin, return
Astro.redirect("/login") or an appropriate denial response. Locate the
Math.random() usage and Astro.redirect call in the admin dashboard handler and
swap them for a call to your existing session/auth helpers (or add a new
requireAdmin(session) function) so only authorized admins can access the page.

In `@apps/icbe/src/pages/api/get-elements.ts`:
- Around line 6-9: Promise.all([getProvenData(), getDisprovenData()]) will
reject if either GitLab fetch fails; wrap the parallel calls in a try/catch (or
use Promise.allSettled) inside the API handler so that failures from
getProvenData or getDisprovenData are caught and the route returns a stable JSON
error payload (e.g., { error: true, message: "...", details?: ... }) with an
appropriate HTTP status instead of letting the framework throw; update the
handler that calls Promise.all to log the underlying error and return that
consistent JSON response.

In `@apps/icbe/src/pages/dashboard/index.astro`:
- Around line 5-7: The current guard using Math.random() in index.astro is a
placeholder and must be replaced with a real authentication/session check:
remove the Math.random() check and instead call your auth/session validation
(for example a getSessionFromRequest or verifySession/validateToken helper) to
determine if the user is authenticated, then if not authenticated call
Astro.redirect("/login") or the appropriate route; update any references in
apps/icbe/src/pages/dashboard/index.astro and ensure the logic uses the real
session/auth function (e.g., verifySession, getSession, isAuthenticated) rather
than Math.random(), and propagate user info into the page when auth succeeds.

In `@apps/icbe/src/utils/gitlab.ts`:
- Around line 1-15: The module currently imports GITLAB_ACCESS_TOKEN and
GITLAB_PROJECT_ID at module scope and constructs api = new Gitlab(...) which
causes a hard build-time dependency; change this to validate the presence of
GITLAB_ACCESS_TOKEN/GITLAB_PROJECT_ID via an optional env/schema check and
lazily initialize the Gitlab client only when needed (e.g., replace the
top-level api with a function like getGitlabClient() that returns null or throws
a controlled error when the env is missing), and update any code that uses api
to call getGitlabClient() first; keep BRANCH and BASE_DATA_DIR constants but
ensure functions that perform GitLab operations (those that reference api,
Gitlab, GITLAB_ACCESS_TOKEN, or GITLAB_PROJECT_ID) perform the runtime guard so
OSS builds succeed without private secrets.
- Around line 72-81: saveToCloud currently writes full-file updates blindly via
api.Commits.create which allows lost updates under concurrent requests; change
saveToCloud to perform optimistic concurrency: before creating the commit, fetch
the latest file contents (use api.RepositoryFiles.show or equivalent) for the
files updated by getUpdateAction, merge the caller's changes into that fresh
content, then attempt the commit and include an optimistic check (e.g., pass the
repository's current commit id/last_commit_id or verify file blob SHA if the
GitLab API supports it); on commit conflict (or non-matching last_commit_id),
retry the fetch/merge/commit cycle a few times before failing. Ensure you update
references to saveToCloud, getUpdateAction, api.Commits.create,
GITLAB_PROJECT_ID and BRANCH in the implementation so the merged data is always
based on the latest remote state.

In `@apps/icbe/src/utils/submit-elements.ts`:
- Around line 57-60: In getProvenToSave(), the call to getUpdatedMetaInfo(...)
incorrectly passes type: "disproven" so proven submissions update the wrong
counters; change the payload to pass type: "proven" when calling
getUpdatedMetaInfo (referencing the getProvenToSave function and the
getUpdatedMetaInfo helper) so the metadata/history branching uses the correct
"proven" branch and count value is accurate.
- Around line 79-84: The dedup logic in submit-elements (where existing,
elements and combined are built) only removes identical object references;
change it to deduplicate by the element.name property instead: produce a
combined array that preserves first instance per unique name (e.g., merge
existing then elements and filter by seen names using a Set of names) before
calling getUpdatedMetaInfo and computing count; update the variable combined
used with getUpdatedMetaInfo so count reflects unique names rather than object
identity.

In `@package.json`:
- Line 18: The "test" npm script currently runs "bun run test" which recursively
invokes itself; update the top-level "test" script to use Bun's workspace filter
like the existing "build:apps" pattern (use bun -F "apps/*" test or equivalent)
so it runs tests only in app workspaces, and change the apps/icbe package.json
"test" script to "bun test" to use Bun's native runner; locate the "test" script
in package.json and mirror the workspace filter approach used by "build:apps" to
prevent recursion.

---

Nitpick comments:
In `@apps/icbe/package.json`:
- Line 14: The package.json "test" script currently uses the wrapper invocation
"bun run test"; update the "test" script value to use the direct Bun command
"bun test" instead (edit the "test" entry in package.json) so the script invokes
bun test directly per Bun recommendations.

In `@apps/icbe/src/components/UserDashboard.tsx`:
- Around line 19-31: The UserDashboard currently hardcodes isAdmin = false which
makes the admin navigation unreachable; replace the hardcoded flag by deriving
admin status from real state (accept an isAdmin prop on the UserDashboard
component or call the app's auth/session hook to get the current user's roles)
and use that value in the existing Show conditional that wraps Divider/Link
(retain TopBar, Show and Link usage). Ensure the prop or session-derived value
is a boolean named isAdmin so existing conditional logic (Show when={isAdmin})
continues to work.

In `@apps/icbe/src/pages/dashboard/index.astro`:
- Line 9: The file currently hardcodes canSubmitElements = false which disables
the element submission UI; replace the hardcoded value with a proper feature
flag or config check (e.g., read from an environment/config value or a feature
toggle) where canSubmitElements is computed at runtime, or if the false value is
intentional for the public release add a clear inline comment next to the
canSubmitElements declaration explaining that it is intentionally disabled and
describing when/how it will be enabled (e.g., via ENABLE_ELEMENT_SUBMIT env var
or a backend-permission check) and reference the variable name canSubmitElements
in your change.

In `@apps/icbe/src/pages/index.astro`:
- Around line 6-8: The metadata variables title, description, and canonical are
set to null which yields missing meta tags; replace these nulls in the index
page by assigning sensible defaults or environment-driven values (e.g., a site
title string, a short description, and the canonical URL) or, if intentionally
left blank, add TODO comments next to the constants to make the intent explicit;
update the constants named title, description, and canonical so downstream
head/meta rendering has real values or clear TODOs.

In `@apps/icbe/src/utils/respond-json.ts`:
- Around line 3-10: The respondWithJSON function always forces status 200 and
fixed headers; change its signature (respondWithJSON<T extends JsonLike>(data:
T, options?: { status?: number; headers?: HeadersInit })) so callers can
override status and headers; merge default headers { "Content-Type":
"application/json" } with options.headers and use options.status || 200 for the
Response creation inside respondWithJSON to construct the Response with the
requested status and headers and return { response, data } as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c8e32981-af82-4a05-82f7-e27d397a09bd

📥 Commits

Reviewing files that changed from the base of the PR and between 95d9d6d and ad08eb4.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (37)
  • .github/workflows/ci.yml
  • .gitignore
  • apps/icbe/README.md
  • apps/icbe/astro.config.ts
  • apps/icbe/package.json
  • apps/icbe/public/.assetsignore
  • apps/icbe/src/actions/index.ts
  • apps/icbe/src/actions/submit-elements.ts
  • apps/icbe/src/components/AdminDashboard.tsx
  • apps/icbe/src/components/UserDashboard.tsx
  • apps/icbe/src/components/dashboard/SubmitDisprovenElementsSection.tsx
  • apps/icbe/src/components/dashboard/SubmitProvenElementsSection.tsx
  • apps/icbe/src/components/ui/Button.tsx
  • apps/icbe/src/components/ui/Divider.tsx
  • apps/icbe/src/components/ui/Link.tsx
  • apps/icbe/src/layouts/Layout.astro
  • apps/icbe/src/pages/admin/dashboard.astro
  • apps/icbe/src/pages/api/get-elements.ts
  • apps/icbe/src/pages/dashboard/index.astro
  • apps/icbe/src/pages/index.astro
  • apps/icbe/src/schemas/data/disproven.ts
  • apps/icbe/src/schemas/data/history.ts
  • apps/icbe/src/schemas/data/index.ts
  • apps/icbe/src/schemas/data/metadata.ts
  • apps/icbe/src/schemas/data/proven.ts
  • apps/icbe/src/schemas/index.ts
  • apps/icbe/src/styles/global.css
  • apps/icbe/src/utils/gitlab.ts
  • apps/icbe/src/utils/merge-data.ts
  • apps/icbe/src/utils/respond-json.ts
  • apps/icbe/src/utils/submit-elements.ts
  • apps/icbe/src/worker-configuration.d.ts
  • apps/icbe/tailwind.config.ts
  • apps/icbe/tests/index.test.ts
  • apps/icbe/tsconfig.json
  • apps/icbe/wrangler.jsonc
  • package.json

Comment on lines +12 to +29
const SubmitDisprovenElementsResultContainer = (props: {
state: SubmitState;
}) => (
<Show when={props.state.status === "complete" && props.state} keyed>
{(state) => (
<p
class={`mt-4 p-4 rounded-md ${
state.success
? "bg-green-50 dark:bg-green-950"
: "bg-red-50 dark:bg-red-950"
}`}
>
{state.success
? "Elements submitted successfully!"
: "Elements submission failed."}
</p>
)}
</Show>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Surface action failures in the result container.

Line 15 only renders feedback for status === "complete", but Lines 49-57 set status: "error" on both failure paths. Rejected submissions are currently silent in the UI.

Also applies to: 49-57

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/components/dashboard/SubmitDisprovenElementsSection.tsx` around
lines 12 - 29, The result container currently only shows feedback when
props.state.status === "complete", so errors set as status === "error" (from the
submission paths) are not shown; update SubmitDisprovenElementsResultContainer
to render for both complete and error statuses (e.g., Show when
props.state.status === "complete" || props.state.status === "error") and use the
passed-in state.success or state.status to decide styling and message so
rejected submissions display an error message; ensure you reference the same
Show usage and the props.state value in the component.

Comment on lines +63 to +65
<textarea
class="text-white p-1 min-h-64"
placeholder="Enter disproven elements, one per line"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Textarea content will be unreadable on the default background.

Line 64 forces white text without setting a matching dark background. On the native light <textarea> background, the user's input becomes invisible.

Suggested fix
-        class="text-white p-1 min-h-64"
+        class="min-h-64 p-2 border rounded-md bg-white text-black dark:bg-gray-800 dark:text-white dark:border-gray-700"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<textarea
class="text-white p-1 min-h-64"
placeholder="Enter disproven elements, one per line"
<textarea
class="min-h-64 p-2 border rounded-md bg-white text-black dark:bg-gray-800 dark:text-white dark:border-gray-700"
placeholder="Enter disproven elements, one per line"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/components/dashboard/SubmitDisprovenElementsSection.tsx` around
lines 63 - 65, The textarea in SubmitDisprovenElementsSection.tsx forces white
text via the class "text-white" without a matching dark background, making input
unreadable on the default light textarea; update the textarea's class list to
either remove "text-white" (so it uses the default/OS colors) or pair it with a
dark background utility (e.g., add a bg-slate-800 or bg-gray-900 class and
appropriate focus/border classes) and ensure placeholder styling remains
visible; locate the <textarea> in the SubmitDisprovenElementsSection component
and adjust the class/className accordingly.

Comment on lines +16 to +31
const SubmitProvenElementsResultContainer = (props: { state: SubmitState }) => (
<Show when={props.state.status === "complete" && props.state} keyed>
{(state) => (
<p
class={`mt-4 p-4 rounded-md ${
state.success
? "bg-green-50 dark:bg-green-950"
: "bg-red-50 dark:bg-red-950"
}`}
>
{state.success
? "Elements submitted successfully!"
: "Elements submission failed."}
</p>
)}
</Show>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Render the "error" submit state too.

Line 17 only shows feedback for status === "complete", but Lines 125-133 set status: "error" on validation/network failures. Users get no visible reason when the submit action fails.

Also applies to: 125-133

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/components/dashboard/SubmitProvenElementsSection.tsx` around
lines 16 - 31, SubmitProvenElementsResultContainer only renders when
props.state.status === "complete", so users never see the error state set
elsewhere; update the Show condition to render for both completion and error
(e.g., props.state.status === "complete" || props.state.status === "error") and
change the error branch to display a specific message from the state (use
state.error or state.message if present, falling back to "Elements submission
failed.") so SubmitProvenElementsResultContainer and the SubmitState error
payload are visible to users.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/icbe/src/utils/submit-elements.ts (1)

47-93: Reduce duplicated save-building flow to prevent future drift.

getProvenToSave and getDisprovenToSave share nearly identical orchestration (fetch → combine → metadata/history → payload). Extracting a small internal helper would reduce maintenance risk.

♻️ Suggested refactor sketch
+async function buildSavePayload<TData extends DataProven | DataDisproven>(args: {
+  type: "proven" | "disproven";
+  incoming: TData;
+  getExisting: () => Promise<TData>;
+  merge: (existing: TData, incoming: TData) => TData;
+}): Promise<SaveToCloudData> {
+  const [existing, oldHistory] = await Promise.all([
+    args.getExisting(),
+    getElementsHistory(),
+  ]);
+
+  const combined = args.merge(existing, args.incoming);
+  const { metadata, history } = getUpdatedMetaInfo(oldHistory, {
+    type: args.type,
+    count: combined.length,
+  });
+
+  return {
+    elements: { type: args.type, data: combined } as SaveToCloudData["elements"],
+    history,
+    metadata,
+  };
+}
+
 export async function getProvenToSave(
   elements: DataProven,
 ): Promise<SaveToCloudData> {
-  const [existing, oldHistory] = await Promise.all([
-    getProvenData(),
-    getElementsHistory(),
-  ]);
-  const combined = mergeProvenData(existing, elements);
-  const { metadata, history } = getUpdatedMetaInfo(oldHistory, {
-    type: "proven",
-    count: combined.length,
-  });
-  const dataToSave: SaveToCloudData = {
-    elements: { type: "proven", data: combined },
-    history,
-    metadata,
-  };
-  return dataToSave;
+  return buildSavePayload({
+    type: "proven",
+    incoming: elements,
+    getExisting: getProvenData,
+    merge: mergeProvenData,
+  });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/icbe/src/utils/submit-elements.ts` around lines 47 - 93, Extract a
shared helper (e.g., buildSavePayload) to centralize the common orchestration
used by getProvenToSave and getDisprovenToSave: the helper should accept
(fetchExistingFn, elements, typeTag, combineFn) or equivalent parameters, call
the provided fetchExistingFn and getElementsHistory() in parallel, produce the
combined elements using the combineFn (mergeProvenData for proven, Set-based
dedupe for disproven), call getUpdatedMetaInfo(oldHistory, { type: typeTag,
count: combined.length }), and return the SaveToCloudData payload; then refactor
getProvenToSave to call buildSavePayload(getProvenData, elements, "proven",
mergeProvenData) and getDisprovenToSave to call
buildSavePayload(getDisprovenData, elements, "disproven", (a,b)=>[...new
Set([...a,...b)]).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/icbe/src/utils/submit-elements.ts`:
- Around line 47-93: Extract a shared helper (e.g., buildSavePayload) to
centralize the common orchestration used by getProvenToSave and
getDisprovenToSave: the helper should accept (fetchExistingFn, elements,
typeTag, combineFn) or equivalent parameters, call the provided fetchExistingFn
and getElementsHistory() in parallel, produce the combined elements using the
combineFn (mergeProvenData for proven, Set-based dedupe for disproven), call
getUpdatedMetaInfo(oldHistory, { type: typeTag, count: combined.length }), and
return the SaveToCloudData payload; then refactor getProvenToSave to call
buildSavePayload(getProvenData, elements, "proven", mergeProvenData) and
getDisprovenToSave to call buildSavePayload(getDisprovenData, elements,
"disproven", (a,b)=>[...new Set([...a,...b)]).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eda334bb-5ab7-4a41-9803-7918cb307f0f

📥 Commits

Reviewing files that changed from the base of the PR and between 4fe2da4 and 1548c2b.

📒 Files selected for processing (1)
  • apps/icbe/src/utils/submit-elements.ts

@gameroman gameroman merged commit 3e7ee42 into main Mar 24, 2026
4 checks passed
@gameroman gameroman deleted the oss-web-app branch March 24, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant